//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//********************************************************* 

using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Xml.Serialization;
using Microsoft.TridentWordAddIn.Common;

namespace Microsoft.TridentWordAddIn.Presentation
{
    internal class UserDataManager
    {
        private const string UserDataFileName = @"\UserData.xml";
        private static DataCryptor dataCryptor = new DataCryptor();

        /// <summary>
        /// Initializes a new instance of the <see cref="UserDataManager"/> class.
        /// </summary>
        private UserDataManager()
        { 
        }

        /// <summary>
        /// Gets the data.
        /// </summary>
        /// <returns>UserData</returns>
        public static UserData GetData()
        {
            UserData userData = new UserData();
            StringBuilder path = new StringBuilder(DirectoryHelper.UserTridentDirectory);
            path.Append(UserDataFileName);
            try
            {
                if (File.Exists(path.ToString()))
                {
                    using (FileStream destinationStream = File.OpenRead(path.ToString()))
                    {
                        using (MemoryStream dataStream = dataCryptor.GetDecryptedData(destinationStream))
                        {
                            XmlSerializer serializer = new XmlSerializer(typeof(UserData));
                            userData = serializer.Deserialize(dataStream) as UserData;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex.Message, TraceLevel.Error.ToString());
            }

            return userData;
        }

        /// <summary>
        /// Saves the specified user data.
        /// </summary>
        /// <param name="userData">The user data.</param>
        public static void Save(UserData userData)
        {
            if (userData == null)
            {
                throw new ArgumentNullException("userData");
            }

            foreach (TridentConnection connection in userData.Connections.Values)
            {
                if (!connection.NeedCredentialSave)
                {
                    switch (connection.ConnectionType)
                    {
                        case ConnectionType.Sql:                            
                            userData.Connections[connection.Name].SqlParameters.Password = string.Empty;
                            break;
                        case ConnectionType.Sitka:                            
                            userData.Connections[connection.Name].SitkaParameters.Password = string.Empty;
                            break;
                        case ConnectionType.AmazonWebService:
                            userData.Connections[connection.Name].AmazonParameters.AccessKey = string.Empty;
                            userData.Connections[connection.Name].AmazonParameters.SecretKey = string.Empty;
                            break;
                        case ConnectionType.WebService:
                            userData.Connections[connection.Name].WebServiceParameters.Password = string.Empty;
                            break;
                    }                    
                }
            }
            
            string path = DirectoryHelper.UserTridentDirectory;
            DirectoryHelper.CreateDirectory(path);
            
            string temporaryFilePath = path;   //Application folder path as destination folder for moving tmp files
            path += UserDataFileName;

            Random r = new Random();
            int rand = r.Next(99999);
            temporaryFilePath += @"\Userdatabkup" + rand + ".tmp";
          
            if (File.Exists(path))
            {
                FileHelper.DeleteFile(temporaryFilePath);
                File.Move(path, temporaryFilePath);
            }

            try
            {
                XmlSerializer serializer = new XmlSerializer(typeof(UserData));
                using (MemoryStream dataStream = new MemoryStream())
                {
                    serializer.Serialize(dataStream, userData);
                    dataStream.Position = 0;

                    using (FileStream destinationStream = new FileStream(path, FileMode.CreateNew))
                    {
                        dataCryptor.EncryptAndStoreData(dataStream, destinationStream);
                        Trace.WriteLine("Saved user data", TraceLevel.Info.ToString());
                    }
                }
            }
            catch (Exception e)
            {
                Trace.WriteLine("Exception: " + e, TraceLevel.Error.ToString());

                // restore in the event of an exception
                FileHelper.DeleteFile(path);
                if (File.Exists(temporaryFilePath))
                {
                    File.Move(temporaryFilePath, path);
                }

                throw;
            }

            FileHelper.DeleteFile(temporaryFilePath);
        }
    }
}
